

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=&#34;light&#34;>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="https://cdn.jsdelivr.net/gh/kzwrime/kzwrime.github.io/img/favicon.png">
  <link rel="icon" type="image/png" href="https://tuchuangrrr.oss-cn-shenzhen.aliyuncs.com/img/kunnan.png">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="">
  <meta name="author" content="霜华">
  <meta name="keywords" content="">
  <title>shlab - kunzh</title>

  <link  rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/10.0.0/styles/atelier-lakeside-dark.min.css" />
    
  

  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_pf9vaxs7x7b.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
</head>


<body>
  <header style="height: 60vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/">&nbsp;<strong>kunzh</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/links/">
                <i class="iconfont icon-link-fill"></i>
                友链
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/shuoshuo2/">
                <i class="iconfont icon-speakernotes"></i>
                留言板
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;</a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" href="javascript:">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner intro-2" id="background" parallax=true
         style="background: url('https://rainrime.top/img/SloveniaAlps.jpg') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="container page-header text-center fade-in-up">
            <span class="h2" id="subtitle">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2020-12-20 19:38" pubdate>
        2020年12月20日 晚上
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      2.8k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      55
       分钟
    </span>
  

  
  
    
      <!-- LeanCloud 统计文章PV -->
      <span id="leancloud-post-views-container" class="post-meta" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="leancloud-post-views"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="container nopadding-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto" id="post">
            <!-- SEO header -->
            <h1 style="display: none">shlab</h1>
            
            <div class="markdown-body" id="post-body">
              <pre><code class="hljs c"><span class="hljs-comment">/*</span>
<span class="hljs-comment"> * tsh - A tiny shell program with job control</span>
<span class="hljs-comment"> *</span>
<span class="hljs-comment"> * &lt;Put your name and login ID here&gt;</span>
<span class="hljs-comment"> */</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdlib.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;unistd.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;string.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;ctype.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;signal.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;sys/types.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;sys/wait.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;errno.h&gt;</span></span>

<span class="hljs-comment">/* Misc manifest constants */</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> MAXLINE 1024   <span class="hljs-comment">/* max line size */</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> MAXARGS 128    <span class="hljs-comment">/* max args on a command line */</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> MAXJOBS 16     <span class="hljs-comment">/* max jobs at any point in time */</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> MAXJID 1 &lt;&lt; 16 <span class="hljs-comment">/* max job ID */</span></span>

<span class="hljs-comment">/* Job states */</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> UNDEF 0 <span class="hljs-comment">/* undefined */</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> FG 1    <span class="hljs-comment">/* running in foreground */</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> BG 2    <span class="hljs-comment">/* running in background */</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> ST 3    <span class="hljs-comment">/* stopped */</span></span>

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * Jobs states: FG (foreground), BG (background), ST (stopped)</span>
<span class="hljs-comment"> * Job state transitions and enabling actions:</span>
<span class="hljs-comment"> *     FG -&gt; ST  : ctrl-z</span>
<span class="hljs-comment"> *     ST -&gt; FG  : fg command</span>
<span class="hljs-comment"> *     ST -&gt; BG  : bg command</span>
<span class="hljs-comment"> *     BG -&gt; FG  : fg command</span>
<span class="hljs-comment"> * At most 1 job can be in the FG state.</span>
<span class="hljs-comment"> */</span>

<span class="hljs-comment">/* Global variables */</span>
<span class="hljs-keyword">extern</span> <span class="hljs-keyword">char</span>** environ;   <span class="hljs-comment">/* defined in libc */</span>
<span class="hljs-keyword">char</span> prompt[] = <span class="hljs-string">&quot;tsh&gt; &quot;</span>; <span class="hljs-comment">/* command line prompt (DO NOT CHANGE) */</span>
<span class="hljs-keyword">int</span> verbose = <span class="hljs-number">0</span>;         <span class="hljs-comment">/* if true, print additional output */</span>
<span class="hljs-keyword">int</span> nextjid = <span class="hljs-number">1</span>;         <span class="hljs-comment">/* next job ID to allocate */</span>
<span class="hljs-keyword">char</span> sbuf[MAXLINE];      <span class="hljs-comment">/* for composing sprintf messages */</span>

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">job_t</span> &#123;</span>           <span class="hljs-comment">/* The job struct */</span>
  <span class="hljs-keyword">pid_t</span> pid;             <span class="hljs-comment">/* job PID */</span>
  <span class="hljs-keyword">int</span> jid;               <span class="hljs-comment">/* job ID [1, 2, ...] */</span>
  <span class="hljs-keyword">int</span> state;             <span class="hljs-comment">/* UNDEF, BG, FG, or ST */</span>
  <span class="hljs-keyword">char</span> cmdline[MAXLINE]; <span class="hljs-comment">/* command line */</span>
&#125;;
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">job_t</span> <span class="hljs-title">jobs</span>[<span class="hljs-title">MAXJOBS</span>];</span> <span class="hljs-comment">/* The job list */</span>
<span class="hljs-comment">/* End global variables */</span>

<span class="hljs-comment">/* Function prototypes */</span>

<span class="hljs-comment">/* Here are the functions that you will implement */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">eval</span><span class="hljs-params">(<span class="hljs-keyword">char</span>* cmdline)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">builtin_cmd</span><span class="hljs-params">(<span class="hljs-keyword">char</span>** argv)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">do_bgfg</span><span class="hljs-params">(<span class="hljs-keyword">char</span>** argv)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">waitfg</span><span class="hljs-params">(<span class="hljs-keyword">pid_t</span> pid)</span></span>;

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sigchld_handler</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sig)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sigtstp_handler</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sig)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sigint_handler</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sig)</span></span>;

<span class="hljs-comment">/* Here are helper routines that we&#x27;ve provided for you */</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">parseline</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>* cmdline, <span class="hljs-keyword">char</span>** argv)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sigquit_handler</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sig)</span></span>;

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">clearjob</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* job)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">initjobs</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">maxjid</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">addjob</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs, <span class="hljs-keyword">pid_t</span> pid, <span class="hljs-keyword">int</span> state, <span class="hljs-keyword">char</span>* cmdline)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">deletejob</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs, <span class="hljs-keyword">pid_t</span> pid)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">pid_t</span> <span class="hljs-title">fgpid</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs)</span></span>;
<span class="hljs-function">struct <span class="hljs-keyword">job_t</span>* <span class="hljs-title">getjobpid</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs, <span class="hljs-keyword">pid_t</span> pid)</span></span>;
<span class="hljs-function">struct <span class="hljs-keyword">job_t</span>* <span class="hljs-title">getjobjid</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs, <span class="hljs-keyword">int</span> jid)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">pid2jid</span><span class="hljs-params">(<span class="hljs-keyword">pid_t</span> pid)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">listjobs</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs)</span></span>;

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">usage</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">unix_error</span><span class="hljs-params">(<span class="hljs-keyword">char</span>* msg)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">app_error</span><span class="hljs-params">(<span class="hljs-keyword">char</span>* msg)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handler_t</span><span class="hljs-params">(<span class="hljs-keyword">int</span>)</span></span>;
<span class="hljs-function"><span class="hljs-keyword">handler_t</span>* <span class="hljs-title">Signal</span><span class="hljs-params">(<span class="hljs-keyword">int</span> signum, <span class="hljs-keyword">handler_t</span>* handler)</span></span>;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * main - The shell&#x27;s main routine</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span>** argv)</span> </span>&#123;
  <span class="hljs-keyword">char</span> c;
  <span class="hljs-keyword">char</span> cmdline[MAXLINE];
  <span class="hljs-keyword">int</span> emit_prompt = <span class="hljs-number">1</span>; <span class="hljs-comment">/* emit prompt (default) */</span> <span class="hljs-comment">/* 输出提示 */</span>

  <span class="hljs-comment">/* Redirect stderr to stdout (so that driver will get all output</span>
<span class="hljs-comment">   * on the pipe connected to stdout) */</span>
  dup2(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);

  <span class="hljs-comment">/* Parse the command line */</span>
  <span class="hljs-keyword">while</span> ((c = getopt(argc, argv, <span class="hljs-string">&quot;hvp&quot;</span>)) != EOF) &#123;
    <span class="hljs-keyword">switch</span> (c) &#123;
      <span class="hljs-keyword">case</span> <span class="hljs-string">&#x27;h&#x27;</span>: <span class="hljs-comment">/* print help message */</span>
        usage();
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">&#x27;v&#x27;</span>:      <span class="hljs-comment">/* emit additional diagnostic(诊断) info */</span>
        verbose = <span class="hljs-number">1</span>; <span class="hljs-comment">/* 冗长的 */</span>
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">&#x27;p&#x27;</span>:          <span class="hljs-comment">/* don&#x27;t print a prompt */</span>
        emit_prompt = <span class="hljs-number">0</span>; <span class="hljs-comment">/* handy for automatic testing */</span>
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">default</span>:
        usage();
    &#125;
  &#125;

  <span class="hljs-comment">/* Install the signal handlers */</span>

  <span class="hljs-comment">/* These are the ones you will need to implement */</span>
  Signal(SIGINT, sigint_handler);   <span class="hljs-comment">/* ctrl-c */</span>
  Signal(SIGTSTP, sigtstp_handler); <span class="hljs-comment">/* ctrl-z */</span>
  Signal(SIGCHLD, sigchld_handler); <span class="hljs-comment">/* Terminated or stopped child */</span>

  <span class="hljs-comment">/* This one provides a clean way to kill the shell */</span>
  Signal(SIGQUIT, sigquit_handler);

  <span class="hljs-comment">/* Initialize the job list */</span>
  initjobs(jobs);

  <span class="hljs-comment">/* Execute the shell&#x27;s read/eval loop */</span>
  <span class="hljs-keyword">while</span> (<span class="hljs-number">1</span>) &#123;
    <span class="hljs-comment">/* Read command line */</span>
    <span class="hljs-keyword">if</span> (emit_prompt) &#123;
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%s&quot;</span>, prompt);
      fflush(<span class="hljs-built_in">stdout</span>);
    &#125;
    <span class="hljs-keyword">if</span> ((fgets(cmdline, MAXLINE, <span class="hljs-built_in">stdin</span>) == <span class="hljs-literal">NULL</span>) &amp;&amp; ferror(<span class="hljs-built_in">stdin</span>))
      app_error(<span class="hljs-string">&quot;fgets error&quot;</span>);
    <span class="hljs-keyword">if</span> (feof(<span class="hljs-built_in">stdin</span>)) &#123; <span class="hljs-comment">/* End of file (ctrl-d) */</span>
      fflush(<span class="hljs-built_in">stdout</span>);
      <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
    &#125;

    <span class="hljs-comment">/* Evaluate the command line */</span>
    eval(cmdline);
    fflush(<span class="hljs-built_in">stdout</span>);
    fflush(<span class="hljs-built_in">stdout</span>);
  &#125;

  <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>); <span class="hljs-comment">/* control never reaches here */</span>
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * eval - Evaluate the command line that the user has just typed in</span>
<span class="hljs-comment"> *</span>
<span class="hljs-comment"> * If the user has requested a built-in command (quit, jobs, bg or fg)</span>
<span class="hljs-comment"> * then execute it immediately. Otherwise, fork a child process and</span>
<span class="hljs-comment"> * run the job in the context of the child. If the job is running in</span>
<span class="hljs-comment"> * the foreground, wait for it to terminate and then return.  Note:</span>
<span class="hljs-comment"> * each child process must have a unique process group ID so that our</span>
<span class="hljs-comment"> * background children don&#x27;t receive SIGINT (SIGTSTP) from the kernel</span>
<span class="hljs-comment"> * when we type ctrl-c (ctrl-z) at the keyboard.</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">eval</span><span class="hljs-params">(<span class="hljs-keyword">char</span>* cmdline)</span> </span>&#123;
  <span class="hljs-keyword">char</span>* argv[MAXARGS]; <span class="hljs-comment">/* Argument list execve() */</span>
  <span class="hljs-keyword">char</span> buf[MAXLINE];   <span class="hljs-comment">/* Holds modified command line */</span>
  <span class="hljs-keyword">int</span> bg = <span class="hljs-number">0</span>;          <span class="hljs-comment">/* Should the job run in bg or fg? */</span>
  <span class="hljs-keyword">pid_t</span> pid = <span class="hljs-number">-1</span>;      <span class="hljs-comment">/* Process id */</span>
  <span class="hljs-keyword">sigset_t</span> mask_all, mask_old, mask_chld;

  <span class="hljs-comment">/* let passing argv without argc safer */</span>
  <span class="hljs-built_in">memset</span>(argv, <span class="hljs-number">0</span>, MAXARGS * <span class="hljs-keyword">sizeof</span>(<span class="hljs-keyword">char</span>*));

  <span class="hljs-built_in">strcpy</span>(buf, cmdline);
  bg = parseline(buf, argv);

  sigfillset(&amp;mask_all);
  sigemptyset(&amp;mask_chld);
  sigaddset(&amp;mask_chld, SIGCHLD);

  <span class="hljs-keyword">if</span> (argv[<span class="hljs-number">0</span>] == <span class="hljs-literal">NULL</span>) <span class="hljs-keyword">return</span>; <span class="hljs-comment">/* Ignore empty lines */</span>

  <span class="hljs-keyword">if</span> (!builtin_cmd(argv)) &#123;
    <span class="hljs-comment">/* avoid such case: child --&gt; exit -(SIG_CHLD)-&gt; delete job -&gt; addjob */</span>
    sigprocmask(SIG_BLOCK, &amp;mask_chld, &amp;mask_old);
    <span class="hljs-keyword">if</span> (!(pid = fork())) &#123;
      <span class="hljs-comment">/* the signal set of the child should be reset */</span>
      sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);

      <span class="hljs-comment">/* let each child process must have a unique process group ID */</span>
      setpgid(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>);

      <span class="hljs-keyword">if</span> (execve(argv[<span class="hljs-number">0</span>], argv, environ) &lt; <span class="hljs-number">0</span>) &#123;
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%s: Command not found\n&quot;</span>, argv[<span class="hljs-number">0</span>]);
        fflush(<span class="hljs-built_in">stdout</span>);
        <span class="hljs-built_in">exit</span>(<span class="hljs-number">1</span>);
      &#125;
      <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
    &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (pid &lt; <span class="hljs-number">0</span>) &#123;
      sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;fork error\n&quot;</span>);
      <span class="hljs-keyword">return</span>;
    &#125;
    sigprocmask(SIG_BLOCK, &amp;mask_all, <span class="hljs-literal">NULL</span>);
    addjob(jobs, pid, bg ? BG : FG, cmdline); <span class="hljs-comment">/* bg = 1(bg) or 0(fg) */</span>
    <span class="hljs-comment">// printf(&quot;hello\n&quot;);</span>
    <span class="hljs-comment">// fflush(stdout);</span>
    <span class="hljs-comment">/* SIG_CHLD should be blocked before waitfg */</span>
    <span class="hljs-comment">// sigprocmask(SIG_SETMASK, &amp;mask_chld, NULL);</span>
    sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);

    <span class="hljs-comment">/* Parent waits for foreground job to terminate */</span>
    <span class="hljs-keyword">if</span> (!bg) &#123;
      waitfg(pid);
      <span class="hljs-comment">// waitpid(pid, NULL, 0);</span>
    &#125; <span class="hljs-keyword">else</span> &#123; <span class="hljs-comment">/* or output the background job info */</span>
      <span class="hljs-comment">/* Protect accesses to shared global data structures</span>
<span class="hljs-comment">       * by blocking all signals</span>
<span class="hljs-comment">       */</span>
      sigprocmask(SIG_BLOCK, &amp;mask_all, <span class="hljs-literal">NULL</span>);
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;[%d] (%d) %s&quot;</span>, pid2jid(pid), pid, cmdline);
      fflush(<span class="hljs-built_in">stdout</span>);
      sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);

      <span class="hljs-comment">// printf(&quot;showend\n&quot;);</span>
    &#125;
  &#125;
  <span class="hljs-keyword">return</span>;
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * parseline - Parse the command line and build the argv array.</span>
<span class="hljs-comment"> *</span>
<span class="hljs-comment"> * Characters enclosed in single quotes are treated as a single</span>
<span class="hljs-comment"> * argument.  Return true if the user has requested a BG job, false if</span>
<span class="hljs-comment"> * the user has requested a FG job.</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">parseline</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>* cmdline, <span class="hljs-keyword">char</span>** argv)</span> </span>&#123;
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">char</span> <span class="hljs-built_in">array</span>[MAXLINE]; <span class="hljs-comment">/* holds local copy of command line */</span>
  <span class="hljs-keyword">char</span>* buf = <span class="hljs-built_in">array</span>;          <span class="hljs-comment">/* ptr that traverses command line */</span>
  <span class="hljs-keyword">char</span>* delim;                <span class="hljs-comment">/* points to first space delimiter */</span>
  <span class="hljs-keyword">int</span> argc;                   <span class="hljs-comment">/* number of args */</span>
  <span class="hljs-keyword">int</span> bg;                     <span class="hljs-comment">/* background job? */</span>

  <span class="hljs-built_in">strcpy</span>(buf, cmdline);
  buf[<span class="hljs-built_in">strlen</span>(buf) - <span class="hljs-number">1</span>] = <span class="hljs-string">&#x27; &#x27;</span>;   <span class="hljs-comment">/* replace trailing &#x27;\n&#x27; with space */</span>
  <span class="hljs-keyword">while</span> (*buf &amp;&amp; (*buf == <span class="hljs-string">&#x27; &#x27;</span>)) <span class="hljs-comment">/* ignore leading spaces */</span>
    buf++;

  <span class="hljs-comment">/* Build the argv list */</span>
  argc = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">if</span> (*buf == <span class="hljs-string">&#x27;\&#x27;&#x27;</span>) &#123;
    buf++;
    delim = <span class="hljs-built_in">strchr</span>(buf, <span class="hljs-string">&#x27;\&#x27;&#x27;</span>);
  &#125; <span class="hljs-keyword">else</span> &#123;
    delim = <span class="hljs-built_in">strchr</span>(buf, <span class="hljs-string">&#x27; &#x27;</span>);
  &#125;

  <span class="hljs-keyword">while</span> (delim) &#123;
    argv[argc++] = buf;
    *delim = <span class="hljs-string">&#x27;\0&#x27;</span>;
    buf = delim + <span class="hljs-number">1</span>;
    <span class="hljs-keyword">while</span> (*buf &amp;&amp; (*buf == <span class="hljs-string">&#x27; &#x27;</span>)) <span class="hljs-comment">/* ignore spaces */</span>
      buf++;

    <span class="hljs-keyword">if</span> (*buf == <span class="hljs-string">&#x27;\&#x27;&#x27;</span>) &#123;
      buf++;
      delim = <span class="hljs-built_in">strchr</span>(buf, <span class="hljs-string">&#x27;\&#x27;&#x27;</span>);
    &#125; <span class="hljs-keyword">else</span> &#123;
      delim = <span class="hljs-built_in">strchr</span>(buf, <span class="hljs-string">&#x27; &#x27;</span>);
    &#125;
  &#125;
  argv[argc] = <span class="hljs-literal">NULL</span>;

  <span class="hljs-keyword">if</span> (argc == <span class="hljs-number">0</span>) <span class="hljs-comment">/* ignore blank line */</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;

  <span class="hljs-comment">/* should the job run in the background? */</span>
  <span class="hljs-keyword">if</span> ((bg = (*argv[argc - <span class="hljs-number">1</span>] == <span class="hljs-string">&#x27;&amp;&#x27;</span>)) != <span class="hljs-number">0</span>) &#123;
    argv[--argc] = <span class="hljs-literal">NULL</span>;
  &#125;
  <span class="hljs-keyword">return</span> bg;
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * builtin_cmd - If the user has typed a built-in command then execute</span>
<span class="hljs-comment"> *    it immediately.</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">builtin_cmd</span><span class="hljs-params">(<span class="hljs-keyword">char</span>** argv)</span> </span>&#123;
  <span class="hljs-keyword">sigset_t</span> mask_new, mask_old;
  sigfillset(&amp;mask_new); <span class="hljs-comment">/* Set all signals in SET */</span>

  <span class="hljs-comment">/* quit command */</span>
  <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">strcmp</span>(argv[<span class="hljs-number">0</span>], <span class="hljs-string">&quot;quit&quot;</span>)) &#123;
    <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
  &#125;
  <span class="hljs-comment">/* fg, bg : deal with foreground or background */</span>
  <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">strcmp</span>(argv[<span class="hljs-number">0</span>], <span class="hljs-string">&quot;fg&quot;</span>) || !<span class="hljs-built_in">strcmp</span>(argv[<span class="hljs-number">0</span>], <span class="hljs-string">&quot;bg&quot;</span>)) &#123;
    do_bgfg(argv);
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
  &#125;
  <span class="hljs-comment">/* jobs : list all jobs */</span>
  <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">strcmp</span>(argv[<span class="hljs-number">0</span>], <span class="hljs-string">&quot;jobs&quot;</span>)) &#123;
    <span class="hljs-comment">/* needs to access jobs */</span>
    sigprocmask(SIG_BLOCK, &amp;mask_new, &amp;mask_old);
    listjobs(jobs);
    sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
  &#125;
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; <span class="hljs-comment">/* not a builtin command */</span>
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * do_bgfg - Execute the builtin bg and fg commands</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">do_bgfg</span><span class="hljs-params">(<span class="hljs-keyword">char</span>** argv)</span> </span>&#123;
  <span class="hljs-keyword">int</span> jid = <span class="hljs-number">0</span>, pid = <span class="hljs-number">0</span>;
  <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">job_t</span>* <span class="hljs-title">job</span>;</span>
  <span class="hljs-keyword">sigset_t</span> mask_all, mask_old;

  sigfillset(&amp;mask_all);

  <span class="hljs-keyword">if</span> (argv[<span class="hljs-number">1</span>] == <span class="hljs-literal">NULL</span>) &#123;
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%s command requires PID or %%jobid argument\n&quot;</span>, argv[<span class="hljs-number">0</span>]);
    fflush(<span class="hljs-built_in">stdout</span>);
    <span class="hljs-keyword">return</span>;
  &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (argv[<span class="hljs-number">2</span>] != <span class="hljs-literal">NULL</span>) &#123;
    <span class="hljs-comment">/* invalid case, but it seens that &quot;tshref.out&quot; didn&#x27;t provide the case */</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Too many arguments for \&quot;%s\&quot;&quot;</span>, argv[<span class="hljs-number">0</span>]);
    <span class="hljs-keyword">return</span>;
  &#125;
  <span class="hljs-keyword">if</span> (argv[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>] == <span class="hljs-string">&#x27;%&#x27;</span>) &#123; <span class="hljs-comment">/* jid */</span>
    <span class="hljs-keyword">if</span> (!(jid = atoi(argv[<span class="hljs-number">1</span>] + <span class="hljs-number">1</span>))) &#123;
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%s: argument must be a PID or %%jobid\n&quot;</span>, argv[<span class="hljs-number">0</span>]);
      <span class="hljs-keyword">return</span>;
    &#125;;
    sigprocmask(SIG_BLOCK, &amp;mask_all, &amp;mask_old);
    job = getjobjid(jobs, jid);
    sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);
    <span class="hljs-keyword">if</span> (!job) &#123;
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%s: No such job\n&quot;</span>, argv[<span class="hljs-number">1</span>]);
      <span class="hljs-keyword">return</span>;
    &#125;
  &#125; <span class="hljs-keyword">else</span> &#123; <span class="hljs-comment">/* pid */</span>
    <span class="hljs-keyword">if</span> (!(pid = atoi(argv[<span class="hljs-number">1</span>]))) &#123;
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%s: argument must be a PID or %%jobid\n&quot;</span>, argv[<span class="hljs-number">0</span>]);
      <span class="hljs-keyword">return</span>;
    &#125;
    sigprocmask(SIG_BLOCK, &amp;mask_all, &amp;mask_old);
    job = getjobpid(jobs, pid);
    sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);
    <span class="hljs-keyword">if</span> (!job) &#123;
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;(%d): No such process\n&quot;</span>, pid);
      <span class="hljs-keyword">return</span>;
    &#125;
  &#125;
  <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">strcmp</span>(argv[<span class="hljs-number">0</span>], <span class="hljs-string">&quot;bg&quot;</span>)) &#123;
    job-&gt;state = BG;
    kill(-job-&gt;pid, SIGCONT);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;[%d] (%d) %s&quot;</span>, job-&gt;jid, job-&gt;pid, job-&gt;cmdline);
  &#125; <span class="hljs-keyword">else</span> &#123;
    job-&gt;state = FG;
    kill(-job-&gt;pid, SIGCONT);
    waitfg(job-&gt;pid);
  &#125;
  <span class="hljs-keyword">return</span>;
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * waitfg - Block until process pid is no longer the foreground process</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">waitfg</span><span class="hljs-params">(<span class="hljs-keyword">pid_t</span> pid)</span> </span>&#123;
  <span class="hljs-comment">// waitpid(pid, NULL, 0);</span>
  <span class="hljs-comment">// return;</span>
  <span class="hljs-keyword">if</span> (!pid) <span class="hljs-keyword">return</span>;
  <span class="hljs-comment">// printf(&quot;wait %d\n&quot;, pid);</span>
  <span class="hljs-comment">// sleep(10);</span>
  <span class="hljs-comment">// printf(&quot;%d\n&quot;, pid == fgpid(jobs));</span>
  <span class="hljs-keyword">sigset_t</span> mask;
  sigemptyset(&amp;mask);
  <span class="hljs-comment">/* TODO I&#x27;m puzzle about this part, fgpid needs to use a for-loop to read jobs</span>
<span class="hljs-comment">   * which is global structures, but block-all should not be use as SIGINT and</span>
<span class="hljs-comment">   * SIGTSTP must be handled */</span>
  <span class="hljs-keyword">while</span> (pid == fgpid(jobs)) &#123;
    sigsuspend(&amp;mask);
    <span class="hljs-comment">// sleep(2);</span>
    <span class="hljs-comment">// printf(&quot;wait\n&quot;);</span>
    <span class="hljs-comment">// listjobs(jobs);</span>
  &#125;
  <span class="hljs-keyword">return</span>;
&#125;

<span class="hljs-comment">/*****************</span>
<span class="hljs-comment"> * Signal handlers</span>
<span class="hljs-comment"> *****************/</span>

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * sigchld_handler - The kernel sends a SIGCHLD to the shell whenever</span>
<span class="hljs-comment"> *     a child job terminates (becomes a zombie), or stops because it</span>
<span class="hljs-comment"> *     received a SIGSTOP or SIGTSTP signal. The handler reaps all</span>
<span class="hljs-comment"> *     available zombie children, but doesn&#x27;t wait for any other</span>
<span class="hljs-comment"> *     currently running children to terminate.</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sigchld_handler</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sig)</span> </span>&#123;
  <span class="hljs-comment">// printf(&quot;sigchld_handler\n&quot;);</span>
  <span class="hljs-comment">// fflush(stdout);</span>

  <span class="hljs-keyword">int</span> errno_old = errno;
  <span class="hljs-keyword">sigset_t</span> mask_all, mask_old;
  <span class="hljs-keyword">pid_t</span> pid = <span class="hljs-number">-1</span>;
  <span class="hljs-keyword">int</span> status;
  <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">job_t</span>* <span class="hljs-title">tjob</span>;</span>

  sigfillset(&amp;mask_all);

  <span class="hljs-keyword">while</span> ((pid = waitpid(<span class="hljs-number">-1</span>, &amp;status, WUNTRACED | WNOHANG)) &gt; <span class="hljs-number">0</span>) &#123;
    <span class="hljs-comment">/* needs to access jobs */</span>
    sigprocmask(SIG_BLOCK, &amp;mask_all, &amp;mask_old);
    tjob = getjobpid(jobs, pid);
    <span class="hljs-comment">// printf(&quot;sigchld_handler: waitpid (%d)\n&quot;, pid);</span>
    <span class="hljs-comment">// printf(&quot;Job [%d] (%d)\n&quot;, tjob-&gt;jid, pid);</span>
    <span class="hljs-comment">// printf(&quot;sigchld_handler: waitpid (%d)\n&quot;, pid);</span>
    <span class="hljs-comment">// fflush(stdout);</span>
    <span class="hljs-keyword">if</span> (WIFSTOPPED(status)) &#123; <span class="hljs-comment">/* child process stoped */</span>
      tjob-&gt;state = ST;
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Job [%d] (%d) stopped by signal %d\n&quot;</span>, tjob-&gt;jid, pid,
             WSTOPSIG(status));
      fflush(<span class="hljs-built_in">stdout</span>);
    &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (WIFSIGNALED(status)) &#123; <span class="hljs-comment">/* child process terminated */</span>
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Job [%d] (%d) terminated by signal %d\n&quot;</span>, tjob-&gt;jid, pid,
             WTERMSIG(status));
      fflush(<span class="hljs-built_in">stdout</span>);
      deletejob(jobs, pid); <span class="hljs-comment">/* reap the terminated child process */</span>
    &#125; <span class="hljs-keyword">else</span> &#123;
      deletejob(jobs, pid);
      <span class="hljs-comment">// printf(&quot;normal exit\n&quot;);</span>
    &#125;
    sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);
  &#125;
  <span class="hljs-comment">// if (errno != ECHILD) &#123;</span>
  <span class="hljs-comment">//   app_error(&quot;waitpid error\n&quot;);</span>
  <span class="hljs-comment">// &#125;</span>
  errno = errno_old;
  <span class="hljs-keyword">return</span>;
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * sigint_handler - The kernel sends a SIGINT to the shell whenver the</span>
<span class="hljs-comment"> *    user types ctrl-c at the keyboard.  Catch it and send it along</span>
<span class="hljs-comment"> *    to the foreground job.</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sigint_handler</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sig)</span> </span>&#123;
  <span class="hljs-keyword">int</span> errno_old = errno;
  <span class="hljs-keyword">sigset_t</span> mask_all, mask_old;
  <span class="hljs-keyword">pid_t</span> pid;

  sigfillset(&amp;mask_all);
  sigprocmask(SIG_BLOCK, &amp;mask_all, &amp;mask_old);
  pid = fgpid(jobs);
  sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);

  <span class="hljs-keyword">if</span> (pid) kill(-pid, SIGINT);

  errno = errno_old;
  <span class="hljs-keyword">return</span>;
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever</span>
<span class="hljs-comment"> *     the user types ctrl-z at the keyboard. Catch it and suspend the</span>
<span class="hljs-comment"> *     foreground job by sending it a SIGTSTP.</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sigtstp_handler</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sig)</span> </span>&#123;
  <span class="hljs-keyword">int</span> errno_old = errno;
  <span class="hljs-keyword">sigset_t</span> mask_all, mask_old;
  <span class="hljs-keyword">pid_t</span> pid;

  sigfillset(&amp;mask_all);
  sigprocmask(SIG_BLOCK, &amp;mask_all, &amp;mask_old);
  pid = fgpid(jobs);
  sigprocmask(SIG_SETMASK, &amp;mask_old, <span class="hljs-literal">NULL</span>);

  <span class="hljs-keyword">if</span> (pid) kill(-pid, SIGTSTP);

  errno = errno_old;
  <span class="hljs-keyword">return</span>;
&#125;

<span class="hljs-comment">/*********************</span>
<span class="hljs-comment"> * End signal handlers</span>
<span class="hljs-comment"> *********************/</span>

<span class="hljs-comment">/***********************************************</span>
<span class="hljs-comment"> * Helper routines that manipulate the job list</span>
<span class="hljs-comment"> **********************************************/</span>

<span class="hljs-comment">/* clearjob - Clear the entries in a job struct */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">clearjob</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* job)</span> </span>&#123;
  job-&gt;pid = <span class="hljs-number">0</span>;
  job-&gt;jid = <span class="hljs-number">0</span>;
  job-&gt;state = UNDEF;
  job-&gt;cmdline[<span class="hljs-number">0</span>] = <span class="hljs-string">&#x27;\0&#x27;</span>;
&#125;

<span class="hljs-comment">/* initjobs - Initialize the job list */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">initjobs</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs)</span> </span>&#123;
  <span class="hljs-keyword">int</span> i;

  <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; MAXJOBS; i++) clearjob(&amp;jobs[i]);
&#125;

<span class="hljs-comment">/* maxjid - Returns largest allocated job ID */</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">maxjid</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs)</span> </span>&#123;
  <span class="hljs-keyword">int</span> i, max = <span class="hljs-number">0</span>;

  <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; MAXJOBS; i++)
    <span class="hljs-keyword">if</span> (jobs[i].jid &gt; max) max = jobs[i].jid;
  <span class="hljs-keyword">return</span> max;
&#125;

<span class="hljs-comment">/* addjob - Add a job to the job list */</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">addjob</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs, <span class="hljs-keyword">pid_t</span> pid, <span class="hljs-keyword">int</span> state, <span class="hljs-keyword">char</span>* cmdline)</span> </span>&#123;
  <span class="hljs-keyword">int</span> i;

  <span class="hljs-keyword">if</span> (pid &lt; <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

  <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; MAXJOBS; i++) &#123;
    <span class="hljs-keyword">if</span> (jobs[i].pid == <span class="hljs-number">0</span>) &#123;
      jobs[i].pid = pid;
      jobs[i].state = state;
      jobs[i].jid = nextjid++;
      <span class="hljs-keyword">if</span> (nextjid &gt; MAXJOBS) nextjid = <span class="hljs-number">1</span>;
      <span class="hljs-built_in">strcpy</span>(jobs[i].cmdline, cmdline);
      <span class="hljs-keyword">if</span> (verbose) &#123;
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Added job [%d] %d %s\n&quot;</span>, jobs[i].jid, jobs[i].pid,
               jobs[i].cmdline);
      &#125;
      <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
    &#125;
  &#125;
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Tried to create too many jobs\n&quot;</span>);
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
&#125;

<span class="hljs-comment">/* deletejob - Delete a job whose PID=pid from the job list */</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">deletejob</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs, <span class="hljs-keyword">pid_t</span> pid)</span> </span>&#123;
  <span class="hljs-keyword">int</span> i;

  <span class="hljs-keyword">if</span> (pid &lt; <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

  <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; MAXJOBS; i++) &#123;
    <span class="hljs-keyword">if</span> (jobs[i].pid == pid) &#123;
      clearjob(&amp;jobs[i]);
      nextjid = maxjid(jobs) + <span class="hljs-number">1</span>;
      <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
    &#125;
  &#125;
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
&#125;

<span class="hljs-comment">/* fgpid - Return PID of current foreground job, 0 if no such job */</span>
<span class="hljs-function"><span class="hljs-keyword">pid_t</span> <span class="hljs-title">fgpid</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs)</span> </span>&#123;
  <span class="hljs-keyword">int</span> i;

  <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; MAXJOBS; i++)
    <span class="hljs-keyword">if</span> (jobs[i].state == FG) <span class="hljs-keyword">return</span> jobs[i].pid;
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
&#125;

<span class="hljs-comment">/* getjobpid  - Find a job (by PID) on the job list */</span>
<span class="hljs-function">struct <span class="hljs-keyword">job_t</span>* <span class="hljs-title">getjobpid</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs, <span class="hljs-keyword">pid_t</span> pid)</span> </span>&#123;
  <span class="hljs-keyword">int</span> i;

  <span class="hljs-keyword">if</span> (pid &lt; <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;
  <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; MAXJOBS; i++)
    <span class="hljs-keyword">if</span> (jobs[i].pid == pid) <span class="hljs-keyword">return</span> &amp;jobs[i];
  <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;
&#125;

<span class="hljs-comment">/* getjobjid  - Find a job (by JID) on the job list */</span>
<span class="hljs-function">struct <span class="hljs-keyword">job_t</span>* <span class="hljs-title">getjobjid</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs, <span class="hljs-keyword">int</span> jid)</span> </span>&#123;
  <span class="hljs-keyword">int</span> i;

  <span class="hljs-keyword">if</span> (jid &lt; <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;
  <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; MAXJOBS; i++)
    <span class="hljs-keyword">if</span> (jobs[i].jid == jid) <span class="hljs-keyword">return</span> &amp;jobs[i];
  <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;
&#125;

<span class="hljs-comment">/* pid2jid - Map process ID to job ID */</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">pid2jid</span><span class="hljs-params">(<span class="hljs-keyword">pid_t</span> pid)</span> </span>&#123;
  <span class="hljs-keyword">int</span> i;

  <span class="hljs-keyword">if</span> (pid &lt; <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; MAXJOBS; i++)
    <span class="hljs-keyword">if</span> (jobs[i].pid == pid) &#123;
      <span class="hljs-keyword">return</span> jobs[i].jid;
    &#125;
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
&#125;

<span class="hljs-comment">/* listjobs - Print the job list */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">listjobs</span><span class="hljs-params">(struct <span class="hljs-keyword">job_t</span>* jobs)</span> </span>&#123;
  <span class="hljs-keyword">int</span> i;

  <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; MAXJOBS; i++) &#123;
    <span class="hljs-keyword">if</span> (jobs[i].pid != <span class="hljs-number">0</span>) &#123;
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;[%d] (%d) &quot;</span>, jobs[i].jid, jobs[i].pid);
      <span class="hljs-keyword">switch</span> (jobs[i].state) &#123;
        <span class="hljs-keyword">case</span> BG:
          <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Running &quot;</span>);
          <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> FG:
          <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Foreground &quot;</span>);
          <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> ST:
          <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Stopped &quot;</span>);
          <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">default</span>:
          <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;listjobs: Internal error: job[%d].state=%d &quot;</span>, i,
                 jobs[i].state);
      &#125;
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%s&quot;</span>, jobs[i].cmdline);
    &#125;
  &#125;
&#125;
<span class="hljs-comment">/******************************</span>
<span class="hljs-comment"> * end job list helper routines</span>
<span class="hljs-comment"> ******************************/</span>

<span class="hljs-comment">/***********************</span>
<span class="hljs-comment"> * Other helper routines</span>
<span class="hljs-comment"> ***********************/</span>

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * usage - print a help message</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">usage</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>&#123;
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Usage: shell [-hvp]\n&quot;</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;   -h   print this message\n&quot;</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;   -v   print additional diagnostic information\n&quot;</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;   -p   do not emit a command prompt\n&quot;</span>);
  <span class="hljs-built_in">exit</span>(<span class="hljs-number">1</span>);
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * unix_error - unix-style error routine</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">unix_error</span><span class="hljs-params">(<span class="hljs-keyword">char</span>* msg)</span> </span>&#123;
  <span class="hljs-built_in">fprintf</span>(<span class="hljs-built_in">stdout</span>, <span class="hljs-string">&quot;%s: %s\n&quot;</span>, msg, strerror(errno));
  <span class="hljs-built_in">exit</span>(<span class="hljs-number">1</span>);
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * app_error - application-style error routine</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">app_error</span><span class="hljs-params">(<span class="hljs-keyword">char</span>* msg)</span> </span>&#123;
  <span class="hljs-built_in">fprintf</span>(<span class="hljs-built_in">stdout</span>, <span class="hljs-string">&quot;%s\n&quot;</span>, msg);
  <span class="hljs-built_in">exit</span>(<span class="hljs-number">1</span>);
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * Signal - wrapper for the sigaction function</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">handler_t</span>* <span class="hljs-title">Signal</span><span class="hljs-params">(<span class="hljs-keyword">int</span> signum, <span class="hljs-keyword">handler_t</span>* handler)</span> </span>&#123;
  <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">sigaction</span> <span class="hljs-title">action</span>, <span class="hljs-title">old_action</span>;</span>

  action.sa_handler = handler;
  sigemptyset(&amp;action.sa_mask); <span class="hljs-comment">/* block sigs of type being handled */</span>
  action.sa_flags = SA_RESTART; <span class="hljs-comment">/* restart syscalls if possible */</span>

  <span class="hljs-keyword">if</span> (sigaction(signum, &amp;action, &amp;old_action) &lt; <span class="hljs-number">0</span>) unix_error(<span class="hljs-string">&quot;Signal error&quot;</span>);
  <span class="hljs-keyword">return</span> (old_action.sa_handler);
&#125;

<span class="hljs-comment">/*</span>
<span class="hljs-comment"> * sigquit_handler - The driver program can gracefully terminate the</span>
<span class="hljs-comment"> *    child shell by sending it a SIGQUIT signal.</span>
<span class="hljs-comment"> */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sigquit_handler</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sig)</span> </span>&#123;
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;Terminating after receipt of SIGQUIT signal\n&quot;</span>);
  <span class="hljs-built_in">exit</span>(<span class="hljs-number">1</span>);
&#125;
</code></pre>
            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/%E6%9D%82/">杂</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/c/">c</a>
                    
                      <a class="hover-with-bg" href="/tags/asm/">asm</a>
                    
                      <a class="hover-with-bg" href="/tags/csapp/">csapp</a>
                    
                      <a class="hover-with-bg" href="/tags/gdb/">gdb</a>
                    
                  </div>
                
              </div>
              
              
                <div class="post-prevnext row">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2050/06/welcome/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">(。・∀・)ノ</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2020/11/Buflab/">
                        <span class="hidden-mobile">buflab</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
              <!-- Comments -->
              <article class="comments" id="comments">
                
                
  <div id="vcomments"></div>
  <script type="text/javascript">
    function loadValine() {
      addScript('https://cdn.staticfile.org/valine/1.4.14/Valine.min.js', function () {
        new Valine({
          el: "#vcomments",
          app_id: "iAgkjaR2s2ws1XXtS5sVxE7H-MdYXbMMI",
          app_key: "vKka6XRlblVTkbKz8jLXx6EQ",
          placeholder: "你是来自评论区的小惊喜吗 ...",
          path: window.location.pathname,
          avatar: "retro",
          meta: ["nick","mail"],
          pageSize: "10",
          lang: "zh-CN",
          highlight: false,
          recordIP: true,
          serverURLs: "",
        });
      });
    }
    waitElementVisible('vcomments', loadValine);
  </script>
  <noscript>Please enable JavaScript to view the <a target="_blank" href="https://valine.js.org" rel="nofollow noopener noopener">comments
      powered by Valine.</a></noscript>


<!-- 
  <div id="vcomments"></div>
  <script type="text/javascript">
    function loadValine() {
      addScript('https://cdn.staticfile.org/valine/1.4.14/Valine.min.js', function () {
        new Valine({
          el: "#vcomments",
          enableQQ: true,
          boolean: true,
          app_id: "iAgkjaR2s2ws1XXtS5sVxE7H-MdYXbMMI",
          app_key: "vKka6XRlblVTkbKz8jLXx6EQ",
          placeholder: "你是来自评论区的小惊喜吗 ...",
          path: "window.location.pathname",
          avatar: "retro",
          meta: "["nick","mail"]",
          pageSize: "10",
          lang: "zh-CN",
          highlight: false,
          recordIP: true,
          serverURLs: "",
            // 设置Bilibili表情包地址
            emojiCDN: '//i0.hdslb.com/bfs/emote/', 
            // 表情title和图片映射
            emojiMaps: {
            "tv_doge": "6ea59c827c414b4a2955fe79e0f6fd3dcd515e24.png",
            "tv_亲亲": "a8111ad55953ef5e3be3327ef94eb4a39d535d06.png",
            "tv_偷笑": "bb690d4107620f1c15cff29509db529a73aee261.png",
            "tv_再见": "180129b8ea851044ce71caf55cc8ce44bd4a4fc8.png",
            "tv_冷漠": "b9cbc755c2b3ee43be07ca13de84e5b699a3f101.png",
            "tv_发怒": "34ba3cd204d5b05fec70ce08fa9fa0dd612409ff.png",
            "tv_发财": "34db290afd2963723c6eb3c4560667db7253a21a.png",
            "tv_可爱": "9e55fd9b500ac4b96613539f1ce2f9499e314ed9.png",
            "tv_吐血": "09dd16a7aa59b77baa1155d47484409624470c77.png",
            "tv_呆": "fe1179ebaa191569b0d31cecafe7a2cd1c951c9d.png",
            "tv_呕吐": "9f996894a39e282ccf5e66856af49483f81870f3.png",
            "tv_困": "241ee304e44c0af029adceb294399391e4737ef2.png",
            "tv_坏笑": "1f0b87f731a671079842116e0991c91c2c88645a.png",
            "tv_大佬": "093c1e2c490161aca397afc45573c877cdead616.png",
            "tv_大哭": "23269aeb35f99daee28dda129676f6e9ea87934f.png",
            "tv_委屈": "d04dba7b5465779e9755d2ab6f0a897b9b33bb77.png",
            "tv_害羞": "a37683fb5642fa3ddfc7f4e5525fd13e42a2bdb1.png",
            "tv_尴尬": "7cfa62dafc59798a3d3fb262d421eeeff166cfa4.png",
            "tv_微笑": "70dc5c7b56f93eb61bddba11e28fb1d18fddcd4c.png",
            "tv_思考": "90cf159733e558137ed20aa04d09964436f618a1.png",
            "tv_惊吓": "0d15c7e2ee58e935adc6a7193ee042388adc22af.png",
            "tv_打脸": "56ab10b624063e966bfcb76ea5dc4794d87dfd47.png",
            "tv_抓狂": "fe31c08edad661d63762b04e17b8d5ae3c71a757.png",
            "tv_抠鼻": "c666f55e88d471e51bbd9fab9bb308110824a6eb.png",
            "tv_斜眼笑": "911f987aa8bc1bee12d52aafe62bc41ef4474e6c.png",
            "tv_无奈": "ea8ed89ee9878f2fece2dda0ea8a5dbfe21b5751.png",
            "tv_晕": "5443c22b4d07fb1907ccc610c8e6db254f2461b7.png",
            "tv_流汗": "cead1c351ab8d79e9f369605beb90148db0fbed3.png",
            "tv_流泪": "7e71cde7858f0cd50d74b0264aa26db612a8a167.png",
            "tv_流鼻血": "c32d39db2737f89b904ca32700d140a9241b0767.png",
            "tv_点赞": "f85c354995bd99e28fc76c869bfe42ba6438eff4.png",
            "tv_生气": "26702dcafdab5e8225b43ffd23c94ac1ff932654.png",
            "tv_生病": "8b0ec90e6b86771092a498c54f09fc94621c1900.png",
            "tv_疑问": "0793d949b18d7be716078349c202c15ff166f314.png",
            "tv_白眼": "c1d59f439e379ee50eef488bcb5e5378e5044ea4.png",
            "tv_皱眉": "72ccad6679fea0d14cce648b4d818e09b8ffea2d.png",
            "tv_目瞪口呆": "0b8cb81a68de5d5365212c99375e7ace3e7891b7.png",
            "tv_睡着": "8b196675b53af58264f383c50ad0945048290b33.png",
            "tv_笑哭": "1abc628f6d4f4caf9d0e7800878f4697abbc8273.png",
            "tv_腼腆": "89712c0d4af73e67f89e35cbc518420380a7f6f4.png",
            "tv_色": "61822c7e9aae5da76475e7892534545336b23a6f.png",
            "tv_调侃": "4bc022533ef31544ca0d72c12c808cf4a1cce3e3.png",
            "tv_调皮": "b9c41de8e82dd7a8515ae5e3cb63e898bf245186.png",
            "tv_鄙视": "6e72339f346a692a495b123174b49e4e8e781303.png",
            "tv_闭嘴": "c9e990da7f6e93975e25fd8b70e2e290aa4086ef.png",
            "tv_难过": "87f46748d3f142ebc6586ff58860d0e2fc8263ba.png",
            "tv_馋": "fc7e829b845c43c623c8b490ee3602b7f0e76a31.png",
            "tv_鬼脸": "0ffbbddf8a94d124ca2f54b360bbc04feb6bbfea.png",
            "tv_黑人问号": "45821a01f51bc867da9edbaa2e070410819a95b2.png",
            "tv_鼓掌": "1d21793f96ef4e6f48b23e53e3b9e42da833a0f6.png"
                // ... 更多表情
            }
        });
      });
    }
    createObserver(loadValine, 'vcomments');
  </script>
      <style>
        #vcomments textarea {
            box-sizing: border-box;
            background: url("/img/v2-f3d5c26e7ac0da80ee72b6dc178d6aa1_b005.gif") 100% 100% no-repeat;
        }
      </style>
  <noscript>Please enable JavaScript to view the <a target="_blank" href="https://valine.js.org" rel="nofollow noopener noopener">comments
      powered by Valine.</a></noscript>
 -->

              </article>
            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div id="tocbot"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->

  <div class="col-lg-7 mx-auto nopadding-md">
    <div class="container custom post-content mx-auto">
      <img src="/img/371905140-ROBOT-WAVING-400px-unscreen(1).gif" srcset="/img/loading.gif" class="rounded mx-auto d-block mt-5" style="width:200px; height:200px;" >
    </div>
  </div>


    
  </main>

  
    <a id="scroll-top-button" href="#" role="button">
      <i class="iconfont icon-arrowup" aria-hidden="true"></i>
    </a>
  

  
    <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
  

  

  

  <footer class="mt-5">
  <div class="text-center py-3">
    <div>
      <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a>
      <i class="iconfont icon-love"></i>
      <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener">
        <span>Fluid</span></a>
        <br>
        <span>©2019 - 2020 By</span>
        <a href="https://github.com/rainrime" target="_blank" rel="nofollow noopener"><span>kunzh</span></a>
    </div>
    
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


    

    
  </div>
</footer>


<!-- SCRIPTS -->
<script  src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js" ></script>
<script  src="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/js/bootstrap.min.js" ></script>
<script  src="/js/debouncer.js" ></script>
<script  src="/js/main.js" ></script>

<!-- Plugins -->


  
    <script  src="/js/lazyload.js" ></script>
  



  



  <script defer src="https://cdn.staticfile.org/clipboard.js/2.0.6/clipboard.min.js" ></script>
  <script  src="/js/clipboard-use.js" ></script>



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>





  <script  src="https://cdn.staticfile.org/tocbot/4.11.1/tocbot.min.js" ></script>
  <script>
    $(document).ready(function () {
      var boardCtn = $('#board-ctn');
      var boardTop = boardCtn.offset().top;

      tocbot.init({
        tocSelector: '#tocbot',
        contentSelector: '#post-body',
        headingSelector: 'h1,h2,h3,h4,h5,h6',
        linkClass: 'tocbot-link',
        activeLinkClass: 'tocbot-active-link',
        listClass: 'tocbot-list',
        isCollapsedClass: 'tocbot-is-collapsed',
        collapsibleClass: 'tocbot-is-collapsible',
        collapseDepth: 6,
        scrollSmooth: true,
        headingsOffset: -boardTop
      });
      if ($('.toc-list-item').length > 0) {
        $('#toc').css('visibility', 'visible');
      }
    });
  </script>



  <script  src="https://cdn.staticfile.org/typed.js/2.0.11/typed.min.js" ></script>
  <script>
    var typed = new Typed('#subtitle', {
      strings: [
        '  ',
        "shlab&nbsp;",
      ],
      cursorChar: "_",
      typeSpeed: 70,
      loop: false,
    });
    typed.stop();
    $(document).ready(function () {
      $(".typed-cursor").addClass("h2");
      typed.start();
    });
  </script>



  <script  src="https://cdn.staticfile.org/anchor-js/4.2.2/anchor.min.js" ></script>
  <script>
    anchors.options = {
      placement: "right",
      visible: "hover",
      
      icon: "❡"
      
    };
    var el = "h1,h2,h3,h4,h5,h6".split(",");
    var res = [];
    for (item of el) {
      res.push(".markdown-body > " + item)
    }
    anchors.add(res.join(", "))
  </script>



  <script  src="/js/local-search.js" ></script>
  <script>
    var path = "/local-search.xml";
    var inputArea = document.querySelector("#local-search-input");
    inputArea.onclick = function () {
      searchFunc(path, 'local-search-input', 'local-search-result');
      this.onclick = null
    }
  </script>



  <script  src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css" />

  <script>
    $('#post img:not(.no-zoom img, img[no-zoom]), img[zoom]').each(
      function () {
        var element = document.createElement('a');
        $(element).attr('data-fancybox', 'images');
        $(element).attr('href', $(this).attr('src'));
        $(this).wrap(element);
      }
    );
  </script>





  

  
    <!-- KaTeX -->
    <link  rel="stylesheet" href="https://cdn.staticfile.org/KaTeX/0.11.1/katex.min.css" />
  



  
  
    <script type="text/javascript">
      //定义获取词语下标
      var a_idx = 0;
      jQuery(document).ready(function ($) {
        //点击body时触发事件
        $("body").click(function (e) {
          //需要显示的词语
          var a = new Array("富强", "民主", "文明", "和谐", "自由", "平等", "公正", "法治", "爱国", "敬业", "诚信", "友善");
          //设置词语给span标签
          var $i = $("<span/>").text(a[a_idx]);
          //下标等于原来下标+1  余 词语总数
          a_idx = (a_idx + 1) % a.length;
          //获取鼠标指针的位置，分别相对于文档的左和右边缘。
          //获取x和y的指针坐标
          var x = e.pageX, y = e.pageY;
          //在鼠标的指针的位置给$i定义的span标签添加css样式
          $i.css({
            "z-index": 999,
            "top": y - 20,
            "left": x,
            "position": "absolute",
            "font-weight": "bold",
            "color": rand_color()
          });
          // 随机颜色
          function rand_color() {
            return "rgb(" + ~~(255 * Math.random()) + "," + ~~(255 * Math.random()) + "," + ~~(255 * Math.random()) + ")"
          }
          //在body添加这个标签
          $("body").append($i);
          //animate() 方法执行 CSS 属性集的自定义动画。
          //该方法通过CSS样式将元素从一个状态改变为另一个状态。CSS属性值是逐渐改变的，这样就可以创建动画效果。
          //详情请看http://www.w3school.com.cn/jquery/effect_animate.asp
          $i.animate({
            //将原来的位置向上移动180
            "top": y - 180,
            "opacity": 0
            //1500动画的速度
          }, 1500, function () {
            //时间到了自动删除
            $i.remove();
          });
        });
      })
      ;
    </script>
  



  <script>(function (i, s, o, g, r, a, m) {
      i['DaoVoiceObject'] = r;
      i[r] = i[r] ||
        function () {
          (i[r].q = i[r].q || []).push(arguments);
        };
      i[r].l = 1 * new Date();
      a = s.createElement(o);
      m = s.getElementsByTagName(o)[0];
      a.async = 1;
      a.src = g;
      a.charset = 'utf-8';
      m.parentNode.insertBefore(a, m);
    })(window, document, 'script', ('https:' === document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/244aa65c.js", 'daovoice');
    daovoice('init', {
      app_id: "244aa65c",
    });
    daovoice('update');
  </script>






  <script  src="https://cdn.staticfile.org/mermaid/8.5.0/mermaid.min.js" ></script>
  <script>
    if (window.mermaid) {
      mermaid.initialize({"theme":"default"});
    }
  </script>




  

  

  

  

  

  





</body>
</html>
